#coding=utf-8
from django.db import models

import os,datetime
from decimal import Decimal
from time import sleep

import scraper
from config import DIRNAME
from stutils import float2dec,data2csv
from stvalidator import *

HISTPRICEDIR = DIRNAME + '/data/histprice'
DEALDIR = DIRNAME + '/data/deal'

class Stcode(models.Model):
    
    '''stcode用于记录 、更新stock代码(code)和名称(name)。
    当新股发行or原有股票更改名称后，数据表中就增加条记录。'''
    
    code = models.CharField(max_length=6)
    name = models.CharField(max_length=20)
    created_at = models.DateField(auto_now_add=True)
    
    class Admin:pass
    
    def __unicode__(self):
        return "%s(%s)"%(self.name, self.code)
    
class Tag(models.Model):
    name = models.CharField(max_length=100)
    class Admin:
        pass
    def __unicode__(self):
        return self.name
class Share(models.Model):
    code = models.CharField(max_length=6, unique=True)
    name = models.CharField(max_length=20)
    ipo = models.DateField()
    
    tags = models.ManyToManyField(Tag, null=True,blank=True)
    def __unicode__(self):
        return "%s(%s)"%(self.name, self.code)
        
    class Admin:pass
    
    def histprice2db(self):    
        
        head = ["日期", "开盘价",	"最高价", "收盘价", "最低价","交易量(手)", "交易金额(万元)"]
        data = scraper.get_histprice(self.code, self.ipo)
        
        #put data into csv file
        fn= '%s/%s.csv'%(HISTPRICEDIR , self.code)
        data2csv(data, head, fn)
        
        #validation
        for d in data:
            isValidPricefromSina(d)
        
        #data 2 db
        pre = None
        for d in data:
            e = Exday(share=self, date=d[0])   
            if pre: e.pre = pre
            e.save()
            pre = e
            
            v = int(Decimal( d[5] ) * 100 )
            a = int(Decimal( d[6] ) * 10000 )
            
            dd = [float2dec(i, 2) for i in d[1:5]]
            p = Price(exday=e, start=dd[0], high=dd[1], end=dd[2], low=dd[3], volume=v, amount=a )
            p.save()
            
    def exday_today(self):
        '''get 日期是今日的交易日;'''
        td = datetime.date.today().isoformat()
        try:
            e = self.exday_set.get(date=td)
        except Exday.DoesNotExist:
            return None
        return e
                
    def has_tdprice(self):
        e = self.exday_today()
        if not e:return False
        if e.price:
            return True
        return False
        
    def tdprice2db(self):
        
        td = datetime.date.today().isoformat()
        if self.has_tdprice():
            #print self, "price data(%s) is alread in database."%td
            return
            
        data = scraper.get_tdprice(self.code)
        #print data
        isValidPricefromSina(data)
        
        try:
            e = self.exday_set.get(date=data[0])
        except Exday.DoesNotExist:
            
            e = Exday(share=self, date=data[0])
            try:
                pre = self.exday_set.latest('date')
            except Exday.DoesNotExist:
                pre = None
            if pre: e.pre = pre
            e.save()
        
        d = data
        v = int(Decimal( d[5] ) * 100 )
        a = int(Decimal( d[6] ) * 10000 )
        
        dd = [float2dec(i, 2) for i in d[1:5]]
        p = Price(exday=e, start=dd[0], high=dd[1], end=dd[2], low=dd[3], volume=v, amount=a )
        p.save()

    def ts2db(self):
        i = 1
        while True:
            i = i + 1
            data = scraper.get_ts(self.code)
            if data:break
            if i > 20:
                print "Can not get 流通A股数量of%s"%self.code
                return
            sleep(0.1)
            
        for d in data:
            isValidDate(d[0])
    
        for d in data:
            q = int(d[1])
        
            if q <= 0:
                raise NegativeTSError(self.code)
            
            #check 是否数据已经存在
            try:
                self.tradableshare_set.get(date=d[0])
            except TradableShare.DoesNotExist,e:
                t = TradableShare(share=self, date=d[0], quantity=int(d[1]))
                t.save()

    def get_ts(self, date=None):
        if not date:
            return self.tradableshare_set.latest('date').quantity
        
        for t in self.tradableshare_set.all().order_by('-date'):
            if date >= t.date.isoformat():
                return t.quantity                
    ts = property(fget=get_ts)

class TradableShare(models.Model):
    
    share = models.ForeignKey('Share')
    date = models.DateField()
    quantity = models.IntegerField()
    
    created_at = models.DateField(auto_now_add=True)
    
    def __unicode__(self):
        ltag = unicode('流通A股数量', 'u8')
        return "%s of %s since %s"%(ltag, self.share.name, self.date )
        
    class Admin:pass

class Exday(models.Model):
    
    date = models.DateField()
    share = models.ForeignKey('Share')
    pre = models.ForeignKey('self', unique=True, null=True, blank=True)
    
    def get_nextday(self):
        a = self.exday_set.all()
        if a:
            return a[0]
        return None
    next=property(fget=get_nextday)
    
    def get_price(self):
        a = self.price_set.all()
        if a:
            return a[0]
        return None
    price=property(fget=get_price)
    
    def get_ts(self):
        '''该交易日的流通A股数量'''
        s = self.share
        for t in s.tradableshare_set.all().order_by('-date'):
            if self.date >= t.date:
                return t.quantity
    ts = property(fget=get_ts)
    
    def get_avgprice(self):
        a = self.averageprice_set.all()
        if a:
            return a[0]
        return None
    avgprice=property(fget=get_avgprice)
    
    def get_avgvolume(self):
        a = self.averagevolume_set.all()
        if a:
            return a[0]
        return None
    avgvolume=property(fget=get_avgvolume)
    
    def prenday(self, n):
        cur = self
        for i in range(n):
            pre = cur.pre
            if not pre: return None
            cur = pre
        return cur 
    
    def has_deal(self):
        if self.deal_set.count() == 0:
            return False
        else:
            return True 
            
    def deal2db(self):
        '''get dealdetails and put them in csv file, db '''
        data = scraper.get_deal(self.share.code, self.date.isoformat())
        if not data:pass
        #put data into csv file
        ddir = DEALDIR + '/%s'%self.share.code
        if not os.path.exists ( ddir ):os.mkdir(ddir)
        head = ['时间', '成交量', '成交价',	'性质']
        fn = ddir + '/%s.csv'%self.date.isoformat()
        data2csv(data, head, fn)
        
        #validation       
        for d in data:
            try:
                isValidDealfromSina(d)
            except ValidationError,e:
                print e
                print d                   
                data.remove(d)
                
        for d in data:
            dd = Deal(exday=self, time=d[0], volume=int(d[1]), price=float2dec(d[2], 2),  buyorsell=d[3])
            dd.save()
            
    def liveprice2db(self):
        '''get liveprice and put them in csv file, db'''
        rp, mm5d = get_rtprice(self.share.code)
        
        #need validation
        LivePrice(Exday=self, time=d[1])
    def __unicode__(self):
        jyr = unicode('交易日', 'u8')
        return "%s:%sof%s"%(self.date, jyr, self.share)
    
    class Admin:pass
    
            
class Price(models.Model):
    exday = models.ForeignKey('Exday', unique=True)
    
    start = models.DecimalField( max_digits=8, decimal_places=2, null=True, blank=True)
    end = models.DecimalField( max_digits=8, decimal_places=2, null=True, blank=True)
    
    low = models.DecimalField( max_digits=8, decimal_places=2, null=True, blank=True)
    high = models.DecimalField( max_digits=8, decimal_places=2, null=True, blank=True)
    
    volume = models.IntegerField()
    amount = models.IntegerField()
    
    change = models.DecimalField( max_digits=6, decimal_places=2, null=True, blank=True )
    hsl = models.DecimalField( max_digits=6, decimal_places=2, null=True, blank=True )
    fluctuation = models.DecimalField( max_digits=6, decimal_places=2, null=True, blank=True )
    
    def get_change(self):
        '''涨跌'''  
        pre = self.exday.pre
        if not pre:return None
        
        pe = pre.price.end
        change = ( self.end - pe )/ pe * 100
        change = float2dec(change, 2)
        
        return change
    
    def get_hsl(self):
        '''换手率'''
        d = self.exday.date.isoformat()
        ts = self.exday.ts
        if not ts:
            #like 爱使股份(600652) in ipo day no 流通A股数量信息fromsina
            return None
        hsl = self.volume / float(ts) * 100
        hsl = float2dec(hsl, 2)
        
        return hsl
        
    def get_fluctuation(self):
        '''波动幅度'''
        f = ( self.high - self.low ) / self.end * 100
        f = float2dec(f, 2)
        return f
        
    def save(self):
        self.change = self.get_change()   
        self.hsl = self.get_hsl()
        self.fluctuation = self.get_fluctuation()
        super(Price, self).save()
        
    def __unicode__(self):
        jyr = unicode('交易日', 'u8')
        jgxx = unicode('的价格信息', 'u8')
        
        return "%s%s on %s(%s)"%(self.exday.share.name, jgxx, jyr, self.exday.date)
        
    class Admin:pass

class Deal(models.Model):
    '''amount: 一笔交易的总金额'''
    exday = models.ForeignKey('Exday')
    
    time = models.TimeField()
    price = models.DecimalField( max_digits=6, decimal_places=2, null=True, blank=True)
    volume = models.IntegerField()
    amount = models.IntegerField()
    buyorsell = models.CharField(max_length=1)
    
    def save(self):
        self.amount = self.price * self.volume
        super(Deal, self).save()
        
    def __unicode__(self):
        cjmx = unicode('成交明细', 'u8')
        return "%s on (%s,%s) of %s"%(cjmx, self.exday.date.isoformat(), self.time.isoformat(), self.exday.share.name) 
    
    class Admin:pass

# 实时数据相关部分
def create_today(code):

    s = Share.objects.get(code=code)
    td = datetime.date.today().isoformat()

    try:
        preday = s.exday_set.latest('date')   
    except Exday.DoesNotExist, e:
        preday = None
    e = Exday(share=s, date=td, pre=preday)
    e.save() 
    
    return e
       
class LivePrice(models.Model):
    
    exday = models.ForeignKey('Exday')
    
    time = models.TimeField()
    price = models.DecimalField( max_digits=6, decimal_places=2)
    change = models.DecimalField( max_digits=6, decimal_places=2)
    volume = models.IntegerField()
    amount = models.IntegerField()
    
    #买卖5档
    s1_price = models.DecimalField( max_digits=6, decimal_places=2)
    s1_volume = models.IntegerField()
    s2_price = models.DecimalField( max_digits=6, decimal_places=2)
    s2_volume = models.IntegerField()
    s3_price = models.DecimalField( max_digits=6, decimal_places=2)
    s3_volume = models.IntegerField()
    s4_price = models.DecimalField( max_digits=6, decimal_places=2)
    s4_volume = models.IntegerField()
    s5_price = models.DecimalField( max_digits=6, decimal_places=2)
    s5_volume = models.IntegerField()
    
    b1_price = models.DecimalField( max_digits=6, decimal_places=2)
    b1_volume = models.IntegerField()
    b2_price = models.DecimalField( max_digits=6, decimal_places=2)
    b2_volume = models.IntegerField()
    b3_price = models.DecimalField( max_digits=6, decimal_places=2)
    b3_volume = models.IntegerField()
    b4_price = models.DecimalField( max_digits=6, decimal_places=2)
    b4_volume = models.IntegerField()
    b5_price = models.DecimalField( max_digits=6, decimal_places=2)
    b5_volume = models.IntegerField()
    
    def __unicode__(self):
        ssjgxx = unicode('实时价格信息', 'u8')
        return "%s on (%s,%s) of %s"%(ssjgxx, self.exday.date.isoformat(), self.time.isoformat(), self.exday.share.name)
    
    class Admin:pass

class AveragePrice(models.Model):
    exday = models.ForeignKey(Exday, unique=True)
    
    ap3 = models.DecimalField( max_digits=8, decimal_places=2, null=True, blank=True)
    ap5 = models.DecimalField( max_digits=8, decimal_places=2, null=True, blank=True)
    ap10 = models.DecimalField( max_digits=8, decimal_places=2, null=True, blank=True)
    ap20 = models.DecimalField( max_digits=8, decimal_places=2, null=True, blank=True)
    ap30 = models.DecimalField( max_digits=8, decimal_places=2, null=True, blank=True)
    ap60 = models.DecimalField( max_digits=8, decimal_places=2, null=True, blank=True)
    ap120 = models.DecimalField( max_digits=8, decimal_places=2, null=True, blank=True)
    ap240 = models.DecimalField( max_digits=8, decimal_places=2, null=True, blank=True)
    class Admin:pass
    
    def __unicode__(self):
        ap =  unicode("平均价格", 'u8')
        return "%s on %s of %s"%(ap, self.exday.date.isoformat(),self.exday.share.name)
        
class AverageVolume(models.Model):
    exday = models.ForeignKey(Exday, unique=True)
    
    av3 = models.IntegerField(null=True, blank=True)
    av5 = models.IntegerField(null=True, blank=True)
    av10 = models.IntegerField(null=True, blank=True)
    av20 = models.IntegerField(null=True, blank=True)
    av30 = models.IntegerField(null=True, blank=True)
    av60 = models.IntegerField(null=True, blank=True)
    av120 = models.IntegerField(null=True, blank=True)
    av240 = models.IntegerField(null=True, blank=True)
    
    ahsl3 = models.DecimalField( max_digits=6, decimal_places=2, null=True, blank=True )
    ahsl5 = models.DecimalField( max_digits=6, decimal_places=2, null=True, blank=True )
    ahsl10 = models.DecimalField( max_digits=6, decimal_places=2, null=True, blank=True )
    ahsl20 = models.DecimalField( max_digits=6, decimal_places=2, null=True, blank=True )
    ahsl30 = models.DecimalField( max_digits=6, decimal_places=2, null=True, blank=True )
    ahsl60 = models.DecimalField( max_digits=6, decimal_places=2, null=True, blank=True )
    ahsl120 = models.DecimalField( max_digits=6, decimal_places=2, null=True, blank=True )
    ahsl240 = models.DecimalField( max_digits=6, decimal_places=2, null=True, blank=True )
